---@class components
---@field webbert_skitter_inventory component_webbert_skitter_inventory # 只能接受简单的预制物

-- local function on_val(self, value)
    -- self.inst.replica.webbert_skitter_inventory:SetVal(value)
-- end

---@class component_webbert_skitter_inventory
---@field inst ent
---@field itms_data table<PrefabID,integer>
local webbert_skitter_inventory = Class(
---@param self component_webbert_skitter_inventory
---@param inst ent
function(self, inst)
    self.inst = inst
    -- self.val = 0

    self.itms_data = {}
end,
nil,
{
    -- val = on_val,
})

function webbert_skitter_inventory:OnSave()
    local data = {}
    for k,v in pairs(self.itms_data) do
        data[k] = v
    end
    return data
end

function webbert_skitter_inventory:OnLoad(data)
    -- self.val = data.val or 0
    for k,v in pairs(data) do
        self.itms_data[k] = v
    end
end


---comment
---@param itm ent
function webbert_skitter_inventory:GiveSimpleItem(itm)
    local p = itm.prefab
    -- 添加物品
    local num = 1
    if itm.components.stackable then
        num = itm.components.stackable:StackSize() or 1
    end
    self.itms_data[p] = (self.itms_data[p] or 0) + num

    -- 移除实体
    itm:Remove()
end

---将库存转移给某个人
---@param guy ent
function webbert_skitter_inventory:TransferAllItemsToSomeone(guy)
    if guy and guy.components.inventory then
        local src_pos = self.inst:GetPosition()
        for k,v in pairs(self.itms_data) do
            if v and v>0 then
                local itms = self:_spawnPrefabByStack(k,v)
                for _,itm in pairs(itms) do
                    guy.components.inventory:GiveItem(itm,nil,src_pos)
                end
            end
        end
    end
    self:RemoveAllItems()
end

---在当前位置丢下所有物品
---@return ent[] # 返回所有丢下的物品
function webbert_skitter_inventory:DropAllItems()
    local all_items = {}
    local pt = self.inst:GetPosition()
    for k,v in pairs(self.itms_data) do
        if v and v>0 then
            local itms = self:_spawnPrefabByStack(k,v)
            for _,itm in pairs(itms) do
                self:_flingItem(itm,pt)
                table.insert(all_items,itm)
            end
        end
    end
    return all_items
end

---清空库存
function webbert_skitter_inventory:RemoveAllItems()
    self.itms_data = nil
    self.itms_data = {}
end


---成组生成物品
---@param prefa_id PrefabID
---@param num integer
---@return ent[] # 生成的物品表
---@nodiscard
function webbert_skitter_inventory:_spawnPrefabByStack(prefa_id,num)
    local res = {}
    local prefab = SpawnPrefab(prefa_id)
    local maxsize = prefab.components.stackable and prefab.components.stackable.maxsize
    -- 可堆叠,且堆叠数量大于1
    if maxsize and maxsize > 1 then
        local stacks = math.floor(num / maxsize)
        local left = num - maxsize * stacks
        if stacks > 0 then
            for i = 1, stacks do
                local item = SpawnPrefab(prefa_id)
                item.components.stackable:SetStackSize(maxsize)
                table.insert(res,item)
            end
        end
        if left > 0 then
            local item = SpawnPrefab(prefa_id)
            item.components.stackable:SetStackSize(left)
            table.insert(res,item)
        end
    else -- 不可堆叠
        table.insert(res,prefab)
    end
    return res
end

---抛物品
---@param loot ent 预制物
---@param pt Vector3 坐标
---@param min_distance number|nil 最小抛出距离,防止某些单位模型太大,抛出距离太小,导致玩家捡不到物品,可不填
---@param max_distance number|nil 最大抛出距离,可不填
function webbert_skitter_inventory:_flingItem(loot, pt, min_distance, max_distance)
    if loot ~= nil then
        loot.Transform:SetPosition(pt:Get())

        local min_speed = 0
        local max_speed = 2
        local y_speed = 8
        local y_speed_variance = 4

        min_distance = min_distance or 0
        max_distance = max_distance or 2

        if loot.Physics ~= nil then
            local angle = math.random() * TWOPI
            local speed = min_speed + math.random() * (max_speed - min_speed)

            local sinangle = math.sin(angle)
            local cosangle = math.cos(angle)
            loot.Physics:SetVel(speed * cosangle, GetRandomWithVariance(y_speed, y_speed_variance), speed * -sinangle)

            local radius = (min_distance + math.random() * (max_distance - min_distance)) * loot:GetPhysicsRadius(1)
            loot.Transform:SetPosition(pt.x + cosangle * radius, pt.y + 0.5, pt.z - sinangle * radius)
        end
    end
end

---
---@return boolean
function webbert_skitter_inventory:IsNotEmpty()
    for k,v in pairs(self.itms_data) do
        if v and v > 0 then
            return true
        end
    end
    return false
end

return webbert_skitter_inventory